Update and CancelUpdate Methods Example (VC++)

This example demonstrates the Update method in conjunction with the CancelUpdate method.

#import "C:\Program Files\Common Files\System\ADO\msado15.dll" \
    no_namespace rename("EOF", "EndOfFile")

#include <stdio.h>
#include <ole2.h>
#include <malloc.h>
#include <conio.h>
#include "UpdateX.h"

// Function Declartion.
inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
void UpdateX(void);
void UpdateX2(void);
void PrintProviderError(_ConnectionPtr pConnection);
void PrintComError(_com_error &e);

void main()
{
    if(FAILED(::CoInitialize(NULL)))
        return;

     UpdateX();

     //Wait here for user to see the output..
     printf("\nPress any key to continue...");
     getch();
     //Clear the screen for the next display   
     system("cls");

     UpdateX2();

     ::CoUninitialize();
}

//////////////////////////////////////////////////////////
//                                                      //
//      UpdateX Function                                //
//                                                      //
//////////////////////////////////////////////////////////
void UpdateX(void)
{
    HRESULT hr = S_OK;

    // Define ADO object pointers.
    // Initialize pointers on define.
    // These are in the ADODB::  namespace.
    _RecordsetPtr pRstEmployees  = NULL;

    // Define string variables.
    _bstr_t strCnn("Provider=sqloledb;Data Source=srv;"
            "Initial Catalog=Pubs;User Id=sa;Password=;");

    IADORecordBinding   *picRs   = NULL;  // Interface Pointer declared
    CEmployeeRs emprs;             // C++ Class object.

    try
    {
        // Open recordset with names from Employees table.
        TESTHR(pRstEmployees.CreateInstance(__uuidof(Recordset)));
        pRstEmployees->CursorType = adOpenKeyset;
        pRstEmployees->LockType = adLockOptimistic;
        pRstEmployees->Open("SELECT fname, lname FROM Employee "
            "ORDER BY lname",strCnn,adOpenKeyset,adLockOptimistic,
            adCmdText);

        // Store original data.
        _bstr_t strOldFirst = pRstEmployees->Fields->
            GetItem("fname")->Value;
        _bstr_t strOldLast  = pRstEmployees->Fields->
            GetItem("lname")->Value;

        //Change data in edit buffer.
        pRstEmployees->Fields->GetItem("fname")->Value = 
            (_bstr_t)("Linda");
        pRstEmployees->Fields->GetItem("lname")->Value = 
            (_bstr_t)("Kobara");

        // Show contents of buffer and get user input.
        printf("\n\nEdit in progress:\n\n");

        printf("Original data =  %s %s \n",
            (LPSTR)strOldFirst,(LPSTR)strOldLast);

        printf("Data in buffer =  %s %s",
            (LPSTR)(_bstr_t) pRstEmployees->Fields->
            GetItem("fname")->Value,\
            (LPSTR) (_bstr_t) pRstEmployees->Fields->
            GetItem("lname")->Value);

        // Ask if the User wants to Update
        printf("\n\nUse Update to replace the original data with the"
               " buffered data in the Recordset? (y/n): ");
        char chKey = getch();

        if(toupper(chKey) == 'Y')
            pRstEmployees->Update();
        else 
            pRstEmployees->CancelUpdate();

        //Open an IADORecordBinding interface pointer which 
        //we'll use for binding Recordset to a class.
        TESTHR(pRstEmployees->QueryInterface(
            __uuidof(IADORecordBinding),(LPVOID*)&picRs));

        //Bind the Recordset to a C++ Class here.
        TESTHR(picRs->BindToRecordset(&emprs));

        pRstEmployees->MoveFirst();

        // Show the resulting data.
        printf("\nData in recordset =  %s %s", emprs.le_fnameStatus == 
            adFldOK ? emprs.m_sze_fname : "<NULL>",
            emprs.le_lnameStatus == adFldOK ? 
            emprs.m_sze_lname : "<NULL>");

        // Restore original data because this is a demonstration.
        if ((strcmp((char *)strOldFirst,emprs.m_sze_fname) && 
             strcmp((char *)strOldLast,emprs.m_sze_lname)))
        {
            pRstEmployees->Fields->GetItem("fname")->Value = strOldFirst;
            pRstEmployees->Fields->GetItem("lname")->Value = strOldLast;
            pRstEmployees->Update();
        } 

        //Release IADORecordset Interface
        if (picRs)
            picRs->Release();

        // Clean up objects before exit.
        pRstEmployees->Close();
    }

    catch(_com_error &e)
    {    
       // Notify the user of errors if any.
       // Pass a connection pointer accessed from the Recordset.
        _variant_t vtConnect = pRstEmployees->GetActiveConnection();

        // GetActiveConnection returns connect string if connection
        // is not open, else returns Connection object.
        switch(vtConnect.vt)
        {
            case VT_BSTR:
                PrintComError(e);
                break;
            case VT_DISPATCH:
                PrintProviderError(vtConnect);
                break;
            default:
                printf("Errors occured.");
                break;
        }
    }
}

// The next example demonstrates the Update method 
// in conjunction with the AddNew method.

//////////////////////////////////////////////////////////
//                                                      //
//           UpdateX2 Function                          //
//                                                      //
//////////////////////////////////////////////////////////
void UpdateX2(void)
{
    HRESULT hr = S_OK;

    // Define ADO object pointers.
    // Initialize pointers on define.
    // These are in the ADODB::  namespace.
    _ConnectionPtr pConnection        = NULL;
    _RecordsetPtr pRstEmployees = NULL;

    // Define string variables.
    _bstr_t strCnn("Provider=sqloledb;Data Source=srv;"
            "Initial Catalog=Pubs;User Id=sa;Password=;");

    IADORecordBinding   *picRs  = NULL;  // Interface Pointer declared
    CEmployeeRs1 emprs;            // C++ Class object.

    try 
    {
        // Open a connection.   
        TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
         pConnection->Open(strCnn,"","",NULL);

        // Open recordset with data from Employees table.
        TESTHR(pRstEmployees.CreateInstance(__uuidof(Recordset)));
        pRstEmployees->CursorType = adOpenKeyset;
        pRstEmployees->LockType = adLockOptimistic;
        pRstEmployees->Open("Employees",
            _variant_t((IDispatch*)pConnection,true),
            adOpenKeyset, adLockOptimistic,adCmdTable);

        pRstEmployees->AddNew();
        _bstr_t strEmpID = "B-S55555M";
        pRstEmployees->Fields->GetItem("emp_id")->Value = strEmpID;
        pRstEmployees->Fields->GetItem("fname")->Value = 
            (_bstr_t) ("Bill");
        pRstEmployees->Fields->GetItem("lname")->Value = 
            (_bstr_t) ("Sornsin");

        // Show contents of buffer and get user input.
        printf("\n\nAddNew in progress:\n\n");

        printf("Data in buffer = %s ,  %s %s",
            (LPSTR) (_bstr_t) pRstEmployees->Fields->
            GetItem("emp_id")->Value,
            (LPSTR) (_bstr_t) pRstEmployees->Fields->
            GetItem("fname")->Value,
            (LPSTR) (_bstr_t) pRstEmployees->Fields->
            GetItem("lname")->Value);

        printf("\n\nUse Update to save buffer to recordset?(y/n):");
        char chKey = getch();

        if(toupper(chKey) == 'Y')
        {
            pRstEmployees->Update();

            //Open an IADORecordBinding interface pointer which 
            //we'll use for binding Recordset to a class.
            TESTHR(pRstEmployees->QueryInterface(
                __uuidof(IADORecordBinding),(LPVOID*)&picRs));

            //Bind the Recordset to a C++ Class here    
            TESTHR(picRs->BindToRecordset(&emprs));

            // Go to the new record and show the resulting data.
            printf ("\n\nData in recordset =  %s ,  %s %s",
                emprs.le_empidStatus == adFldOK ? 
                emprs.m_sze_empid : "<NULL>",
                emprs.le_fnameStatus == adFldOK ? 
                emprs.m_sze_fname : "<NULL>",
                emprs.le_lnameStatus == adFldOK ? 
                emprs.m_sze_lname : "<NULL>");
        }
        else
        {
            pRstEmployees->CancelUpdate();
            printf("\n\nNo new record added.\n");
        }
        // Delete new data because this is a demonstration.
        _bstr_t strSQLDelete("DELETE FROM Employees WHERE emp_id = '" + 
            strEmpID + "'");
         pConnection->Execute(strSQLDelete ,NULL,adExecuteNoRecords);

        //Release IADORecordset Interface
        if (picRs)
            picRs->Release();

        // Clean up objects before exit.
        pRstEmployees->Close();
        pConnection->Close();
    }

    catch(_com_error &e)
    {
        // Notify the user of errors if any.
        // Pass a connection pointer accessed from the Connection.
        PrintProviderError(pConnection);
        PrintComError(e);
    }
}

//////////////////////////////////////////////////////////
//                                                      //
//       PrintProviderError Function                    //
//                                                      //
//////////////////////////////////////////////////////////
void PrintProviderError(_ConnectionPtr pConnection)
{
    // Print Provider Errors from Connection object.
    // pErr is a record object in the ConnectionÆs Errors collection.
    ErrorPtr    pErr  = NULL;

    if( (pConnection->Errors->Count) > 0)
    {
        long nCount = pConnection->Errors->Count;
        // Collection ranges from 0 to nCount -1.
        for(long i = 0; i < nCount; i++)
        {
            pErr = pConnection->Errors->GetItem(i);
            printf("Error number: %x\t%s\n", pErr->Number, 
                (LPCSTR) pErr->Description);
        }
    }
}

//////////////////////////////////////////////////////////
//                                                      //
//      PrintComError Function                          //
//                                                      //
//////////////////////////////////////////////////////////
void PrintComError(_com_error &e)
{

    _bstr_t bstrSource(e.Source());
    _bstr_t bstrDescription(e.Description());
        
    // Print Com errors.  
    printf("Error\n");
    printf("\tCode = %08lx\n", e.Error());
    printf("\tCode meaning = %s\n", e.ErrorMessage());
    printf("\tSource = %s\n", (LPCSTR) bstrSource);
    printf("\tDescription = %s\n", (LPCSTR) bstrDescription);
}

UpdateX.h

#include "icrsint.h"

//This Class extracts only fname,lname from Employees table.
class CEmployeeRs : public CADORecordBinding
{
BEGIN_ADO_BINDING(CEmployeeRs)
    // fname is the 1st field in the recordset    
    ADO_VARIABLE_LENGTH_ENTRY2(1, adVarChar, m_sze_fname, 
         sizeof(m_sze_fname), le_fnameStatus, FALSE)
    // lname is the 2nd field in the recordset.
    ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_sze_lname, 
         sizeof(m_sze_lname), le_lnameStatus, FALSE)   
 
END_ADO_BINDING()

public:
   CHAR   m_sze_lname[31];
   ULONG  le_lnameStatus;
   CHAR   m_sze_fname[21];
   ULONG  le_fnameStatus;
};

//This Class extracts only empid,fname,lname,from Employees table.
class CEmployeeRs1 : public CADORecordBinding
{
BEGIN_ADO_BINDING(CEmployeeRs1)
    // emp_id is the 1st field in the table.    
    ADO_VARIABLE_LENGTH_ENTRY2(1, adVarChar, m_sze_empid, 
        sizeof(m_sze_empid), le_empidStatus, FALSE)
    // fname is the 2nd field in the table.
   ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_sze_fname, 
         sizeof(m_sze_fname), le_fnameStatus, FALSE)
    // lname is the 4rt field in the table.
   ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_sze_lname, 
         sizeof(m_sze_lname), le_lnameStatus, FALSE)   
   
END_ADO_BINDING()

public:
   CHAR   m_sze_empid[10];
   ULONG  le_empidStatus;
   CHAR   m_sze_lname[31];
   ULONG  le_lnameStatus;
   CHAR   m_sze_fname[21];
   ULONG  le_fnameStatus;   
};